#include "rune_detecter.hpp"

rune_detect::rune_detect(double max_r_area_ratio,
    double min_r_area_ratio,
    double max_target_area_ratio,
    double min_target_area_ratio,
    double thre,
    double max_r_area,
    double min_r_area,
    double max_target_area,
    double min_target_area,
    double max_LengthAndWidth_ratio,
    double min_LengthAndWidth_ratio,
    double the_true_rune_ratio,
    bool target_color)
    : max_r_area_ratio(max_r_area_ratio),
    min_r_area_ratio(min_r_area_ratio),
    max_target_area_ratio(max_target_area_ratio),
    min_target_area_ratio(min_target_area_ratio),
    thre(thre),
    max_r_area(max_r_area),
    min_r_area(min_r_area),
    max_target_area(max_target_area),
    min_target_area(min_target_area),
    max_LengthAndWidth_ratio(max_LengthAndWidth_ratio),
    min_LengthAndWidth_ratio(min_LengthAndWidth_ratio),
    the_true_rune_ratio(the_true_rune_ratio),
    target_color(target_color){ };

bool rune_detect::lineCircleIntersection(Point2f R_center, Point2f target_center, float radius, Point2f& bottom, Point2f& top, Point2f& left, Point2f& right) {
    // 计算直线的方向向量
    Point2f direction = target_center - R_center;
    // 参数化直线方程
    float dx = direction.x;
    float dy = direction.y;
    float fx = R_center.x - target_center.x;
    float fy = R_center.y - target_center.y;
    // 方程的系数
    float a = dx * dx + dy * dy;
    float b = 2 * (fx * dx + fy * dy);
    float c = fx * fx + fy * fy - radius * radius;
    // 解二次方程 ax^2 + bx + c = 0
    float discriminant = b * b - 4 * a * c;
    if (discriminant < 0) {
        // 如果判别式小于0，则没有交点
        return false;
    }
    // 计算t值
    float t1 = (-b - sqrt(discriminant)) / (2 * a);
    float t2 = (-b + sqrt(discriminant)) / (2 * a);
    //判断是top还是bottom
    float k1, k2;
    if (abs(t1) > abs(t2))
    {
        k1 = t2;
        k2 = t1;
    }
    else
    {
        k1 = t1;
        k2 = t2;
    }
    // 计算交点坐标
    bottom = R_center + k1 * direction;
    top = R_center + k2 * direction;
 
    if (dx != 0 && dy != 0)
    {
        Point2f left_tmp, right_tmp;

        float slope_R_T = dy / dx;      // R_center 到 target_center 的斜率
        float slope_vt = -1 / slope_R_T; // 垂直直线的斜率
        
        float sqrt_term = sqrt(1 + slope_vt * slope_vt);
        left_tmp.x = target_center.x + radius / sqrt_term;
        right_tmp.x = target_center.x - radius / sqrt_term;
        left_tmp.y = target_center.y + slope_vt * (radius / sqrt_term);
        right_tmp.y = target_center.y - slope_vt * (radius / sqrt_term);
        cout << "fy :" << fy << endl;
     
        if (fy > 0)
        {
            if (fy < 100&&fx>0)
            {
                if (left_tmp.y > right_tmp.y)
                {
                 
                    left = left_tmp;
                    right = right_tmp;
                }
                else
                {
                    right = left_tmp;
                    left = right_tmp;
                }
            }
            else if (fy < 100 && fx < 0)
            {
                if (left_tmp.y > right_tmp.y)
                {
                    right = left_tmp;
                    left = right_tmp;
                }
                else
                {
                    left = left_tmp;
                    right = right_tmp;
                }
            }
            else {

                if (left_tmp.x > right_tmp.x)
                {
                    right = left_tmp;
                    left = right_tmp;
                }
                else
                {
                    left = left_tmp;
                    right = right_tmp;
                }
            }
          
        }
        else
        {
            if (fy > -100 && fx>0) {
                if (left_tmp.y > right_tmp.y)
                {
                    left = left_tmp;
                    right = right_tmp;
                }
                else
                {
                    right = left_tmp;
                    left = right_tmp;
                }
            }
            else if (fy > -100 && fx < 0)
            {
                if (left_tmp.y > right_tmp.y)
                {
                    right = left_tmp;
                    left = right_tmp;
                }
                else
                {
                    left = left_tmp;
                    right = right_tmp;
                }

            }
            else {
                if (left_tmp.x > right_tmp.x)
                {

                    left = left_tmp;
                    right = right_tmp;
                }
                else
                {
                    right = left_tmp;
                    left = right_tmp;
                }
            }


        }
    }



    if (dx == 0)
    {
        
        if (fy < 0) {
           
            right = Point2f(target_center.x + radius, target_center.y);
            left = Point2f(target_center.x - radius, target_center.y);
        }
        else
        {
            
            right = Point2f(target_center.x - radius, target_center.y);
            left = Point2f(target_center.x + radius, target_center.y);
        }
    }
    if (dy == 0)
    {
        
        if (fx > 0) {
            right = Point2f(target_center.x, target_center.y + radius);
            left = Point2f(target_center.x, target_center.y - radius);
        }
        else
        {
           
            right = Point2f(target_center.x, target_center.y - radius);
            left = Point2f(target_center.x, target_center.y + radius);
        }

    }
    return true;
}


void rune_detect::dispose_img()
{
    vector<Mat> channels;
    // 把一个3通道图像转换成3个单通道图像
    split(frame, channels);

    Mat grayImg;

    //剔除我们不想要的颜色
    //对于图像中红色的物体来说，其rgb分量中r的值最大，g和b在理想情况下应该是0，同理蓝色物体的b分量应该最大,将不想要的颜色减去，剩下的就是我们想要的颜色
    if (target_color == 0) {
        grayImg = channels.at(2) - channels.at(0);//R-B
    }
    else {
        grayImg = channels.at(0) - channels.at(2);//B-R
    }



    Mat gray_img;
    cvtColor(frame, gray_img, cv::COLOR_BGR2GRAY);
    GaussianBlur(gray_img, gray_img, Size(5, 5), 0);
    threshold(gray_img, binary_img, thre, 255, THRESH_BINARY);
    threshold(grayImg, binary_img_2, thre, 255, THRESH_BINARY);
    /*
    Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
    //膨胀
    dilate(binary_img_2, binary_img_2, element);*/

    cv::Mat mask = cv::Mat::zeros(binary_img.size(), CV_8UC1);
    for (int i = 0; i < binary_img.rows; i++)
    {
        for (int t = 0; t < binary_img.cols; t++)
        {
            if (binary_img.at< uchar>(i, t) == 255 && binary_img_2.at< uchar>(i, t) == 255)
            {
                mask.at<uchar>(i, t) = 255;
            }
            else
            {
                mask.at<uchar>(i, t) = 0;
            }
        }
    }
    binary_img_final = mask.clone();
    /*
    Mat struct1 = getStructuringElement(0, Size(3, 3));
    dilate(binary_img, binary_img, struct1, Point(-1, -1), 3);
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    erode(binary_img, binary_img, element, Point(-1, -1), 1);*/
}


bool rune_detect::detect_all(Mat &frame) {
    this->frame = frame.clone();
    dispose_img();
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(binary_img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    for (auto contour : contours)
    {
        if (contour.size() < 5)
        {
            continue;
        }
        Rect roi_b = boundingRect(contour);
        RotatedRect roi_x = minAreaRect(contour);

        double length = roi_x.size.height > roi_x.size.width ? roi_x.size.height : roi_x.size.width;
        double width = roi_x.size.height < roi_x.size.width ? roi_x.size.height : roi_x.size.width;

        bool is_target =
            (double)roi_x.size.area() / (double)roi_b.area() < max_target_area_ratio &&
            (double)roi_x.size.area() / (double)roi_b.area() > min_target_area_ratio &&
            (double)roi_x.size.area() < max_target_area && (double)roi_x.size.area() > min_target_area &&
            width / length > min_LengthAndWidth_ratio &&
            width / length <= max_LengthAndWidth_ratio;

        bool is_R =
            (double)roi_x.size.area() > min_r_area && (double)roi_x.size.area() < max_r_area &&
            (double)roi_x.size.area() / (double)roi_b.area() < max_r_area_ratio &&
            (double)roi_x.size.area() / (double)roi_b.area() > min_r_area_ratio &&
            width / length > min_LengthAndWidth_ratio &&
            width / length <= max_LengthAndWidth_ratio;

        if (is_R)
        {
            Rs.push_back(roi_b);
        }
        if (is_target) {
            Rota_targets.push_back(roi_x);
        }
    }
    if (!Rs.empty() || !Rota_targets.empty())
    {
        return true;
    }
    return false;
}

bool rune_detect::detect_final() {
    //最终的筛选-------------------------------------------------------
    Point center_frame(frame.cols / 2, frame.rows / 2);
    if (Rs.size() > 0)
    {
        sort(Rs.begin(), Rs.end(), [center_frame](Rect a, Rect b) {
            Point a1(a.x, a.y);
            Point b1(b.x, b.y);

            double dis_a = norm(center_frame - a1);
            double dis_b = norm(center_frame - b1);
            return dis_a < dis_b;
            });
        cout << "有R" << endl;
        final_R = Rs[0];
        if (Rota_targets.size() > 0) {

            Rect R = final_R;
            double t = the_true_rune_ratio;
            sort(Rota_targets.begin(), Rota_targets.end(), [R,t](RotatedRect a, RotatedRect b)
                {
                    
                    double dis_a1 = abs(norm(Point2f(R.x + R.width / 2, R.y + R.height / 2) - a.center));
                    double dis_b1 = abs(norm(Point2f(R.x + R.width / 2, R.y + R.height / 2) - b.center));
                    double pro_a1 = abs((((a.size.width + a.size.height) / 2.0) / dis_a1) - t);
                    double pro_b1 = abs((((a.size.width + a.size.height) / 2.0) / dis_b1) - t);
                    return pro_a1 < pro_b1;
                });
            final__Rota_target = Rota_targets[0];
            return true;
        }
    }
    return false;
 
}

void rune_detect::draw_frame()
{
    //绘画-------------------------------------------------------------------
    Point2f R_center(final_R.x + final_R.width / 2, final_R.y + final_R.height / 2);
    Point2f bottom, top, left, right;
    if (final__Rota_target.center.x > 0 && final__Rota_target.center.y > 0 && R_center.x > 0 && R_center.y > 0) {
        if (lineCircleIntersection(R_center, final__Rota_target.center, (final__Rota_target.size.width + final__Rota_target.size.height) / 4, bottom, top, left, right)) {
            cout << "找到角点" << endl;
            line(frame, top, left, Scalar(0, 255, 0), 2);
            line(frame, top, right, Scalar(0, 255, 0), 2);
            line(frame, bottom, left, Scalar(0, 255, 0), 2);
            line(frame, bottom, right, Scalar(0, 255, 0), 2);
            line(frame, left, R_center, Scalar(0, 255, 0), 2);
            line(frame, right, R_center, Scalar(0, 255, 0), 2);
            cv::putText(frame,
                "top",
                top,
                cv::FONT_HERSHEY_SIMPLEX,
                0.8,
                Scalar(0, 0, 255),
                2);
            cv::putText(frame,
                "bottom",
                bottom,
                cv::FONT_HERSHEY_SIMPLEX,
                0.8,
                Scalar(0, 0, 255),
                2);
            cv::putText(frame,
                "left",
                left,
                cv::FONT_HERSHEY_SIMPLEX,
                0.8,
                Scalar(0, 0, 255),
                2);
            cv::putText(frame,
                "right",
                right,
                cv::FONT_HERSHEY_SIMPLEX,
                0.8,
                Scalar(0, 0, 255),
                2);
        }
    }
    //R标的中心点
    circle(frame, R_center, 1, Scalar(0, 255, 0), 2);
    //击打目标的中心点
    circle(frame, final__Rota_target.center, 1, Scalar(0, 255, 0), 2);
    //绘画-------------------------------------------------------------------
}


void rune_detect::show_img()
{
    imshow("frame", frame);
    imshow("binary", binary_img);
    uchar q = waitKey(1);
    if (q == 'q')
    {
        waitKey(0);
    }
}

bool rune_detect::detect(Mat& frame)
{
    bool has_project = detect_all(frame);
    if (has_project)
    {
        cout << 1 << endl;
        bool has_target = detect_final();
        if (has_target)
        {

            draw_frame();
        }
        return true;
    }
    return false;
}

